package com.pan.download5.sync;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.LockSupport;

/**
 * 该类主要是靠信号量Semaphore来实现UnlockAndBlock
 */
public class SemaphoreUnlockAndBlock implements UnlockAndBlock {

    private Map<Integer,Thread> threadMap = new HashMap<>();
    private Semaphore semaphore = new Semaphore(1);

    @Override
    public void lock() {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void unlock() {
        semaphore.release();
    }

    private Semaphore mapOperateSemaphore = new Semaphore(1);
    @Override
    public void unlockAndBlock(int id) {
        try {
            mapOperateSemaphore.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        Thread parkThread = Thread.currentThread();
        threadMap.put(id,parkThread);
        new Thread(()->{
            Semaphore mySemaphore = null;
            while (mySemaphore != semaphore){
                mySemaphore = (Semaphore) LockSupport.getBlocker(parkThread);
            }
            mySemaphore.release();
            mapOperateSemaphore.release();
        }).start();
        LockSupport.park(semaphore);
    }

    @Override
    public void wakeBlockThread(int id) {
        try {
            mapOperateSemaphore.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (threadMap.containsKey(id)){
            Thread thread = threadMap.get(id);
            threadMap.remove(id);
            LockSupport.unpark(thread);
        }
        mapOperateSemaphore.release();
    }

    @Override
    public Thread getBlockerById(int id) {
        try {
            mapOperateSemaphore.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        try {
            Thread thread = threadMap.get(id);
            return thread;
        }finally {
            mapOperateSemaphore.release();
        }
    }
}
